Introduction
Getting Started
App Config File
Entity Schemas
NoLang Script
NoLang Endpoints
Microservices
Storage
Documents / Entity Schemas
contents

Entity Definition in NoLang

Each NoLang app contains at least one entity. They are defined in JSON schema format. Nolang adds some keywords to standard JSON schemas to define schema of entities. An entity schema can be defined as follows:
{
 	//(string) Identifier of this entity
	$id : "entity1" ,
	//(object) List of fields in this entity
	properties : {} ,
	//(object) Storage specification of this entity
	$$storage : ... ,
	//(array) Array of rules for validation or other type of rules
	$$rules : [] ,
	//(array) Array of access of roles to this entity
	$$roles : [] ,
	//(array) List of methods in this entity
	$$methods : [] ,
	//(array) Array of ids of used entities
	$$uses : ["entity2","entity3"] , 
}

  • $id
  • $id is the identifier of this entity. It must be unique in the app. It is better to don't use dot in ids.

  • properties
  • properties shows list of fields in this entity. Each field has a title, type and more attributes.
    {
    	"$id": "products",
    	"title": "products",
    	"properties": {
    		"productKey": {
    			"title": "Product Key",
    			"type": "number"
    		},
    		"productName": {
    			"title": "Name of product",
    			"type": "string",
    			"minLength": 3
    		},
    		"address": {
    			"title": "Address of manufacture",
    			"type": "object",
    			"$ref": "address"
    		},
    		"stores": {
    			"title": "Stores",
    			"description": "List of stores sell this product",
    			"type": "array",
    			"items": {
    				"type": "number",
    				"$$rel": {
    					"schema": "store"
    				}
    			}
    		}
    	}
    }

  • $$storage
  • For each entity we can set its specific $$storage configuration. otherwise NoLang uses the default storage in the app config file. For more information see the Storage section.

  • $$rules
  • In addition to checking the type of each field in the properties keyword, NoLang includes another feature to check more complicated states. By using $$rules, some rules of relationship between fields of an entity can be defined in JSON Logic format. It can also be defined some triggering rules.

    In the below sample, there is an entity with two fields named "status" and "progress". The "progress" is a number between 0 and 10. There are, however, some rules: if "progress" is 0, "status" must be "Not Started" and vice versa. If the "progress" is 10, then the "status" must be "Done". There is another rule with ruleId "triggerRule1" and with ruleType "trigger". It must be run in "afterCreate" rule time. ruleTime can has one value of "beforeCreate", "afterCreate", "beforeUpdate", "afterUpdate", "beforeDelete", "afterDelete", "onSearch", "onRead", "onWiew", "onLoad", "onStorageConnected" and "every". if ruleTime was equal to "every", we must set schedule like a crontab. Finally, we have the ruleDef, a NoLang script which runs at trigger time.
    {
     	//(string) key of this rule
    	ruleId : "check1" ,
    	//(array) which schemas are related to this rule, items are addresses of related INNER nodes 
    	schemas : ['schema1', 'schema2'] ,
    	//(string) title of rule for advisor
    	title : "check value" ,
    	//(string) on [action] [error] [if] do 
    	description : "a description about this rule" ,
    	//(one or array of CRUD actions) this rule will be triggered before Delete for example
    	before : "D" ,
    	//(one action or array of actions) this rule will be triggered after Create or Update for example
    	after : ["C","U"] ,
    	//(string) cron expression for trigger this rule
    	schedule : "0 30 10 * * *" ,
    	//(string) timezone of the schedule
    	timezone : "Asia/Tehran" ,
    	//(string,array) error code(s) which will trigger this rule
    	error : 'ERR2' ,
    	//(object) jsonlogic or object of condition, 
    	//after any trigger this condition will be checked and it is not a trigger itself.
    	condition : {
    		">": [
    				{
    						"var": "field1"
    				},
    				1
    		]
    } ,
    	//(object) jsonlogic or object of condition, for any CRUD action this check must be returns true
    	check : {
    		"!=": [
    				{
    						"var": "data.field1"
    				},
    				"0"
    		]
    } ,
    	//(object) object to be assigned to the object this is created or updated
    	set : {
    		"field3": {
    				"+": [
    						"{{data.field1}}",
    						"{{data.field2}}"
    				]
    		},
    		"field4": "{{ Date.now()}}"
    } ,
    	//(object) on triggering this rule this scripts will be ran
    	script : {
    		"$schema": "schemaX",
    		"$header": {
    				"action": "D",
    				"filter": {
    						"field2": "{{data.field2}}"
    				}
    		}
    } ,
    	//(object) an object or jsonLogic to filter data list after retrieve data
    	filter : {
    		"schoolId": "{{user.schoolId}}"
    } ,
    	//(boolean) run async this rule, default is false
    	async : true ,
    	//(string) message if check failed
    	message : "A message from server" , 
    }

  • $$roles
  • There are a number of access rights associated with an entity, represented by $$roles. A schema without $$roles has no restrictions. access is equal to a set of first letters of Create, Read, Update, Delete or All.
    {
    	"$$roles": [
    		{
    			"roleId": "*",
    			"permissions": [
    				{
    					"access": [
    						"R"
    					]
    				}
    			]
    		},
    		{
    			"roleId": "supervisor",
    			"permissions": [
    				{
    					"access": [
    						"R",
    						"U"
    					]
    				}
    			]
    		},
    		{
    			"roleId": "admin",
    			"permissions": [
    				{
    					"access": [
    						"A"
    					]
    				}
    			]
    		}
    	]
    }

  • $$methods
  • It is possible to have some methods in an entity. Using $$methods we can define methods for entities.
    {
    	"$id": "entity-with-methods",
    	"properties": {},
    	"$methods": [
    		{
    			"name": "sendText",
    			"params": {
    				"mobileNo": {
    					"type": "string"
    				},
    				"text": {
    					"type": "string"
    				}
    			},
    			"handler": [
    				{
    					"$$schema": "sms_queue",
    					"$$header": {
    						"action": "C"
    					},
    					"receiver": "{{params.mobileNo}}",
    					"text": "{{params.text}}"
    				}
    			]
    		},
    		{
    			"name": "wait",
    			"params": {
    				"seconds": {
    					"type": "number"
    				}
    			},
    			"jsHandler": "../methods/myMethods.js"
    		}
    	]
    }
    In the above schema there are two methods. By calling first method it would create an element in the "sms_queue" entity. Next method has a javascript handler. Invoking it would cause an wait. The javascript handler file myMethods.js is like bellow:
    module.exports = {
        wait : async function () {
            await new Promise(resolve => {
                setTimeout(resolve, this.params.seconds*1000)
            })
    
            return {success: true, message: 'waited for '+this.params.seconds+' seconds'}
        }
    }
    For calling methods we must run a NoLang Script with action M.